Read from a Button

Get user input with a button

In this recipe, we look at reading the value from a button. This will allow you to turn things on and off, and lots more!

This illustrates the key concept of reading digital inputs on the Arduino.


Build the Circuit

You will need:

Wire up the circuit as follows:

Enter the Code

Copy the code below and overwrite the code in the Arduino IDE.

// Constants
const int BUTTONPIN = 7;

void setup() {
  // Tell Arduino which pins are input and output
  pinMode(BUTTONPIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  // Set initial LED state
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  // Read the state of the switch into a local variable
  int reading = digitalRead(BUTTONPIN);

  // Set the LED on or off according to the state
  digitalWrite(LED_BUILTIN, reading);
}

Run the Code

Now upload the code to the Arduino.

The LED should start flashing.

Try changing the code so the LED is on when the button is not pressed and off if the button is pressed.

How it Works

The constant BUTTONPIN is the Arduino pin which we will use to read the button value.

In the setup() function, we need to tell the Arduino that we will be receiving inputs on this pin:

pinMode(BUTTONPIN, INPUT);

In the loop, we create a variable which will receive the value we read from the button pin. This will either be HIGH to indicate that the button is being pressed, or LOW to indicate that the button is not being pressed. We read the value from the pin into this variable:

int reading = digitalRead(BUTTONPIN);

Next, we set the LED to match the value of the reading:

digitalWrite(LED_BUILTIN, reading);

Extension: Toggle Button

What if we want a toggle button? This will allow us to switch the LED on and off without having to hold the button down. Here are some code changes to do that:

// Constants
const int BUTTONPIN = 7;

// Variables
int ledState = HIGH;         // the current state of the LED pin

void setup() {
  // Tell Arduino which pins are input and output
  pinMode(BUTTONPIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  // Set initial LED state
  digitalWrite(LED_BUILTIN, ledState);
}

void loop() {
  // Read the state of the switch into a local variable:
  int reading = digitalRead(BUTTONPIN);

  // If the switch is pressed, flip the state
  if (reading == HIGH) 
    ledState = !ledState;

  // Set the LED on or off according to the state
  digitalWrite(LED_BUILTIN, ledState);
}

In this code we create a global variable to record the current led state (on or off, represented by 1 or 0):

int ledState = HIGH;

When we see that the button is pressed, we flip the state.

  if (reading == HIGH) 
ledState = !ledState;

Now we just need to set the LED based on the value of the state variable:

digitalWrite(LED_BUILTIN, ledState);

Here is a short video of it working. But it's not perfect. See the next extension for some improvements.

Extension: Debouncing

When you run the toggle button code, you may find that you sometimes press the button and it doesn't seem to change the LED, or it changes and quickly changes back. What you are experiencing is a phenomenon called bounce.

When you press the button, what you are actually doing is making a physical connection between two pieces of metal. At the microscopic level, the moment the physical connection is made is not clear cut, with the connection being made and broken as the two pieces of metal come together. The Arduino takes readings so fast (millions of times per second) that in the course of you pressing the button, it records lots of state changes. The solution is to read values until a a certain time period elapses. If the reading remains the same after that period, we presume the reading is a solid reading. The following code originated from here.

// Constants
const int BUTTONPIN = 7;

// Variables
int ledState = HIGH;         // the current state of the LED pin
int buttonState;             // the current reading from the button pin
int lastButtonState = LOW;   // the previous reading from the button pin

// The following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(BUTTONPIN, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  // Set initial LED state
  digitalWrite(LED_BUILTIN, ledState);
}

void loop() {
  // Read the state of the switch into a local variable:
  int reading = digitalRead(BUTTONPIN);

  // Check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise

  // If the switch changed, due to noise or pressing
  if (reading != lastButtonState) {
    // Reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // Whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state

    // If the button state has changed
    if (reading != buttonState) {
      buttonState = reading;

      // Only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // Set the LED on or off according to the state
  digitalWrite(LED_BUILTIN, ledState);

  // Save the reading. Next time through the loop, it'll be the lastButtonState
  lastButtonState = reading;
}

Here is a short video of it working.